<template>
    <div class="main-layout">
        <!-- 左侧组件列表 -->
        <div class="source-list">
            <h3>组件列表</h3>
            <div
                    v-for="comp in componentsList"
                    :key="comp.type"
                    class="source-item-wrapper"
            >
                <t-popup trigger="hover" placement="right">
                    <template #default>
                        <div class="source-item">
                            {{ comp.name }}
                            <t-button size="small" @click="addComponent(comp.type)">添加</t-button>
                        </div>
                    </template>
                </t-popup>
            </div>
        </div>

        <!-- 中间 12*12 网格区 -->
        <div ref="gridContainerRef" class="grid-container">
            <div v-for="n in 144" :key="`bg-${n}`" class="grid-cell-bg"></div>

            <!-- 占位格，用于拖拽/缩放预览 -->
            <div
                    v-if="placeholder.visible"
                    class="placeholder-item"
                    :style="placeholderStyle"
            ></div>

            <Vue3DraggableResizable
                    v-for="(comp, index) in placedComponents"
                    :key="comp.id"
                    :x="comp.x"
                    :y="comp.y"
                    :w="comp.w"
                    :h="comp.h"
                    :grid="[gridCellSize.width, gridCellSize.height]"
                    :parent="true"
                    class="placed-item"
                    :resizable="true"
                    :draggable="true"
                    @dragging="(payload) => handleItemDragging(index, payload)"
                    @drag-end="(payload) => handleItemDragEnd(index, payload)"
                    @resize="(payload) => handleItemResizing(index, payload)"
                    @resize-end="(payload) => handleItemResizeEnd(index, payload)"
            >
                <component
                        :is="componentMap[comp.type]"
                        :width="comp.w"
                        :height="comp.h"
                />
            </Vue3DraggableResizable>
        </div>
    </div>
</template>

<script setup>
    import { ref, reactive, computed, onMounted, onBeforeUnmount } from "vue";
    import Vue3DraggableResizable from "vue3-draggable-resizable";
    import "vue3-draggable-resizable/dist/Vue3DraggableResizable.css";

    import CarouselBanner from "../components/Swiper.vue";
    import NewsList from "../components/Timeline.vue";

    const gridContainerRef = ref(null);
    const gridCellSize = reactive({ width: 0, height: 0 });
    const placedComponents = ref([]);

    // 左侧组件列表
    const componentsList = [
        { type: "carousel", name: "轮播图" },
        { type: "news", name: "新闻动态" },
    ];

    const componentMap = {
        carousel: CarouselBanner,
        news: NewsList,
    };

    // 占位符
    const placeholder = reactive({
        visible: false,
        x: 0,
        y: 0,
        w: 0,
        h: 0
    });

    const placeholderStyle = computed(() => ({
        display: placeholder.visible ? "block" : "none",
        left: placeholder.x + "px",
        top: placeholder.y + "px",
        width: placeholder.w + "px",
        height: placeholder.h + "px"
    }));

    // 检查两个组件是否重叠
    const isOverlap = (a, b) => !(a.x + a.w <= b.x || b.x + b.w <= a.x || a.y + a.h <= b.y || b.y + b.h <= a.y);

    // 添加组件
    const addComponent = (type) => {
        const gridW = gridCellSize.width;
        const gridH = gridCellSize.height;
        if (!gridW || !gridH) return;

        const placed = placedComponents.value;
        const newComp = { id: Date.now(), type, w: 4 * gridW, h: 4 * gridH, x: 0, y: 0 };
        let row = 0, col = 0, maxPerRow = 3;

        while (true) {
            newComp.x = col * gridW;
            newComp.y = row * gridH;
            const conflict = placed.some(c => isOverlap(c, newComp));
            if (!conflict) break;

            col++;
            if (col >= maxPerRow) {
                col = 0;
                row++;
            }
        }

        placed.push(newComp);
    };

    // 拖拽/缩放处理函数
    const handleItemDragging = (index, payload) => {
        const comp = placedComponents.value[index];
        comp.x = payload.x;
        comp.y = payload.y;

        placeholder.visible = true;
        placeholder.x = Math.round(comp.x / gridCellSize.width) * gridCellSize.width;
        placeholder.y = Math.round(comp.y / gridCellSize.height) * gridCellSize.height;
        placeholder.w = comp.w;
        placeholder.h = comp.h;

        resolveCollisions(index);
    };

    const handleItemDragEnd = (index, payload) => {
        const comp = placedComponents.value[index];
        const gw = gridCellSize.width;
        const gh = gridCellSize.height;

        // 先对齐网格
        let x = Math.round(payload.x / gw) * gw;
        let y = Math.round(payload.y / gh) * gh;

        // 吸附对齐：与其他组件边缘相差 8px 以内即吸附
        const snapDist = 8;
        placedComponents.value.forEach((c, i) => {
            if (i === index) return;
            // 左边缘吸附到对方右边缘
            if (Math.abs(x - (c.x + c.w)) < snapDist) x = c.x + c.w;
            // 右边缘吸附到对方左边缘
            if (Math.abs(x + comp.w - c.x) < snapDist) x = c.x - comp.w;
            // 上边缘吸附到对方下边缘
            if (Math.abs(y - (c.y + c.h)) < snapDist) y = c.y + c.h;
            // 下边缘吸附到对方上边缘
            if (Math.abs(y + comp.h - c.y) < snapDist) y = c.y - comp.h;
        });

        comp.x = x;
        comp.y = y;
        placeholder.visible = false;
        resolveCollisions(index);
    };

    const handleItemResizing = (index, payload) => {
        const comp = placedComponents.value[index];
        comp.w = payload.w;
        comp.h = payload.h;

        placeholder.visible = true;
        placeholder.x = comp.x;
        placeholder.y = comp.y;
        placeholder.w = comp.w;
        placeholder.h = comp.h;

        resolveCollisions(index);
    };

    const handleItemResizeEnd = (index, payload) => {
        const gw = gridCellSize.width;
        const gh = gridCellSize.height;
        const comp = placedComponents.value[index];

        comp.w = Math.max(2 * gw, Math.round(payload.w / gw) * gw);
        comp.h = Math.max(2 * gh, Math.round(payload.h / gh) * gh);

        placeholder.visible = false;
        resolveCollisions(index);
    };


    // 递归处理碰撞
    const resolveCollisions = (movedIndex) => {
        const movedComp = placedComponents.value[movedIndex];
        placedComponents.value.forEach((c, i) => {
            if (i === movedIndex) return;
            if (isOverlap(movedComp, c)) {
                c.y = movedComp.y + movedComp.h;
                resolveCollisions(i);
            }
        });
    };

    // 更新网格尺寸
    const updateGridCellSize = () => {
        if (!gridContainerRef.value) return;
        const rect = gridContainerRef.value.getBoundingClientRect();
        gridCellSize.width = rect.width / 12;
        gridCellSize.height = rect.height / 12;

        placedComponents.value.forEach(c => {
            c.x = Math.round(c.x / gridCellSize.width) * gridCellSize.width;
            c.y = Math.round(c.y / gridCellSize.height) * gridCellSize.height;
            c.w = Math.max(gridCellSize.width, Math.round(c.w / gridCellSize.width) * gridCellSize.width);
            c.h = Math.max(gridCellSize.height, Math.round(c.h / gridCellSize.height) * gridCellSize.height);
        });
    };

    let resizeObserver;
    onMounted(() => {
        updateGridCellSize();
        resizeObserver = new ResizeObserver(updateGridCellSize);
        resizeObserver.observe(gridContainerRef.value);
    });
    onBeforeUnmount(() => resizeObserver.disconnect());
</script>

<style>
    .main-layout { display: flex; height: 100vh; }
    .source-list { width: 220px; padding: 20px; border-right: 1px solid #ccc; background-color: #f9f9f9; }
    .source-item-wrapper { margin-bottom: 12px; }
    .source-item { padding: 10px; border: 1px solid #ccc; border-radius: 4px; background-color: #fff; text-align: center; cursor: pointer; }
    .grid-container { flex-grow: 1; position: relative; display: grid; grid-template-columns: repeat(12, 1fr); grid-template-rows: repeat(12, 1fr); background-color: #f0f2f5; overflow: hidden; }
    .grid-cell-bg { border: 1px dashed rgba(0,0,0,0.1); box-sizing: border-box; }
    .placed-item { border: 2px solid #4489ff; border-radius: 6px; background-color: rgba(222,237,255,0.9); }
    .placed-item.vdr-dragging, .placed-item.vdr-resizing { z-index: 100; border-color: #0d6efd; box-shadow: 0 8px 24px rgba(0,0,0,0.2); opacity: 0.8; }
    .placeholder-item { position: absolute; background-color: rgba(68,137,255,0.3); border: 2px dashed #4489ff; border-radius: 6px; pointer-events: none; z-index: 99; transition: all 0.1s ease; }
</style>
